﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using System.Drawing;
using System.Runtime.InteropServices;

namespace cnris.uc
{
    public partial class reportrich : RichTextBox
    {
        private bool changing = false;
        private ContextMenuStrip cm;
        private ContextMenuStrip cmRight;
        public Hashtable htMenus = null;
        //private License license = null;
        private int menuIdx0 = 0;
        private int menuIdx1 = 0;
        private bool MoveCurbyArrow = false;
        private string richtext = string.Empty;
        private string selectitem = string.Empty;
        private bool showMenuOnDoubleClick = false;
        private bool showMenuWhenChangItem = false;
        private bool mSendThis = true;     //启用控件拖动的时候判断拖的是自己的文本还是其他地方拖过来的 true为自己 false 为其他地方

        private bool mViewSett = false;
        /// <summary>
        /// 是否显示设置菜单
        /// </summary>
        public bool SViewSett
        {
            get { return mViewSett; }
            set { mViewSett = value; }
        }

        public reportrich()
        {
            InitializeComponent();
            this.htMenus = new Hashtable();
            base.MouseUp += new MouseEventHandler(this.txt_MouseUp);
            base.MouseDoubleClick += new MouseEventHandler(this.txt_MouseDoubleClick);
            this.cm = new ContextMenuStrip(this.components);
            this.cm.Name = "cm";
            this.cm.Size = new Size(0x99, 0x1a);
            this.cm.ItemClicked += new ToolStripItemClickedEventHandler(this.cm_ItemClicked);
            this.cm.KeyPress += new KeyPressEventHandler(this.cm_KeyPress);
        }

        public void AppendItemText(string text, bool AppendOnEnd)
        {
            if (text.IndexOf('\r') != -1)
            {
                text = text.Replace("\r", "");
            }
            int startindex = AppendOnEnd ? this.GetItemLastIndex() : base.SelectionStart;
            if ((startindex >= 0) && (startindex <= this.Text.Length))
            {
                Hashtable htMenuItem = new Hashtable();
                if (text.IndexOf('[') != -1)
                {
                    string resulttext = string.Empty;
                    this.CreateMenuText(startindex, text, out resulttext, htMenuItem);
                    text = resulttext;
                }
                if (AppendOnEnd)
                {
                    this.SelectionLength = 0;
                    base.SelectionStart = startindex;
                }
                this.SelectedText = text;
                Font prototype = this.Font;
                foreach (DictionaryEntry entry in htMenuItem)
                {
                    int start = int.Parse(entry.Key.ToString());
                    string str2 = entry.Value.ToString();
                    if (str2.Trim().Length == 0)
                    {
                        base.Select(start, str2.Length);
                        base.SelectionColor = Color.FromArgb(0x1f, 0x1f, 0xff);
                        base.SelectionFont = new Font(prototype, FontStyle.Underline);
                    }
                    else
                    {
                        int index = str2.IndexOf('|');
                        base.Select(start, index);
                        base.SelectionColor = Color.FromArgb(this.menuIdx1, this.menuIdx0, 0xff);
                        base.SelectionFont = new Font(prototype, FontStyle.Underline);
                        this.htMenus.Add((this.menuIdx1 * 30) + this.menuIdx0, entry.Value);
                        if (this.menuIdx0 >= 30)
                        {
                            this.menuIdx1++;
                            this.menuIdx0 = 1;
                        }
                        else
                        {
                            this.menuIdx0++;
                        }
                    }
                }
                base.SelectionStart = base.Text.Length;
            }
        }

        private int GetItemLastIndex()
        {
            int num6;
            this.changing = true;
            RichTextBox box = this.CopyRichText();
            try
            {
                int num5;
                int selectionStart = base.SelectionStart;
                int selectionLength = this.SelectionLength;
                box.SelectionLength = 0;
                int num3 = selectionStart;
                int num4 = num3;
                if (box.SelectionFont.Bold)
                {
                    for (num5 = selectionStart + 1; num5 <= box.TextLength; num5++)
                    {
                        box.SelectionStart = num5;
                        if (!box.SelectionFont.Bold)
                        {
                            break;
                        }
                        num4++;
                    }
                }
                if (num4 < box.Text.Length)
                {
                    num3 = num4;
                    for (num5 = num3 + 1; num5 <= box.TextLength; num5++)
                    {
                        box.SelectionStart = num5;
                        if (box.SelectionFont.Bold)
                        {
                            break;
                        }
                        num4++;
                    }
                }
                num6 = num4;
            }
            catch
            {
                throw;
            }
            finally
            {
                box.Dispose();
                this.changing = false;
            }
            return num6;
        }

        private RichTextBox CopyRichText()
        {
            RichTextBox box = new RichTextBox();
            box.Rtf = base.Rtf;
            box.SelectionStart = base.SelectionStart;
            box.SelectionLength = base.SelectionLength;
            return box;
        }

        private void CreateMenuText(int startindex, string origintext, out string resulttext, Hashtable htMenuItem)
        {
            origintext = origintext.Replace("[]", "[  ]");
            StringBuilder builder = new StringBuilder();
            StringBuilder builder2 = new StringBuilder();
            string[] strArray = origintext.Split(new char[] { '[' });
            bool flag = true;
            string str = string.Empty;
            foreach (string str2 in strArray)
            {
                int index = str2.IndexOf(']');
                if (index > 0)
                {
                    string str3 = str2.Substring(0, index);
                    if (str3.IndexOf('|') != -1)
                    {
                        //int num3 = (startindex + builder.Length) + 1;
                        int num3 = (startindex + builder.Length);
                        htMenuItem.Add(num3.ToString(), str3);
                        str = str3.Substring(0, str3.IndexOf('|'));
                        //str = " " + str + " ";
                        builder.Append(str);
                        str = str.Replace("\r\n", "\n");
                        builder2.Append(str);
                        str = str2.Substring(index + 1);
                        //str = str2.Substring(index);
                        builder.Append(str);
                        str = str.Replace("\r\n", "\n");
                        builder2.Append(str);
                        if (flag)
                        {
                            flag = false;
                        }
                        goto Label_0219;
                    }
                    if (str3.Trim().Length == 0)
                    {
                        htMenuItem.Add((startindex + builder.Length).ToString(), str3);
                        str = str3;
                        if (!this.MoveCurbyArrow)
                        {
                            this.MoveCurbyArrow = true;
                        }
                        builder.Append(str);
                        str = str.Replace("\r\n", "\n");
                        builder2.Append(str);
                        str = str2.Substring(index + 1);
                        builder.Append(str);
                        str = str.Replace("\r\n", "\n");
                        builder2.Append(str);
                        if (flag)
                        {
                            flag = false;
                        }
                        goto Label_0219;
                    }
                }
                if (flag)
                {
                    flag = false;
                }
                else
                {
                    builder.Append("[");
                }
                builder.Append(str2);
            Label_0219: ;
            }
            resulttext = builder.ToString();
        }

        private void GetMenuTextStartAndLen(ref int start, ref int len)
        {
            int num4;
            RichTextBox box = this.CopyRichText();
            start = box.SelectionStart;
            int num = start;
            int num2 = start;
            int num3 = box.SelectionColor.ToArgb();
            for (num4 = num2; num4 >= 0; num4--)
            {
                box.Select(num4, 0);
                if (!(box.SelectionFont.Underline && (box.SelectionColor.ToArgb() == num3)))
                {
                    break;
                }
                start = num4;
            }
            if (start > 0)
            {
                //start--;
            }
            for (num4 = num2 + 1; num4 <= box.Text.Length; num4++)
            {
                box.Select(num4, 0);
                if (!(box.SelectionFont.Underline && (box.SelectionColor.ToArgb() == num3)))
                {
                    break;
                }
                num = num4;
            }
            if ((box.Text[start] == '\n') || (box.Text[start] == '\r'))
            {
                for (num4 = start; num4 < num; num4++)
                {
                    if ((box.Text[num4] != '\n') && (box.Text[num4] != '\r'))
                    {
                        start = num4;
                        break;
                    }
                }
            }
            len = num - start;
        }

        private void ShowMenu(Point mousePosition)
        {
            int key = (base.SelectionColor.R * 30) + base.SelectionColor.G;
            if (this.htMenus.Contains(key))
            {
                string[] strArray = this.htMenus[key].ToString().Split(new char[] { '|' });
                if (!this.showMenuWhenChangItem)
                {
                    int start = 0;
                    int len = 0;
                    this.GetMenuTextStartAndLen(ref start, ref len);
                    string str = this.Text.Substring(start, len);
                    bool flag = false;
                    foreach (string str2 in strArray)
                    {
                        if (str2.Equals(str))
                        {
                            flag = true;
                            break;
                        }
                    }
                    if (!flag)
                    {
                        return;
                    }
                }
                this.cm.Items.Clear();
                foreach (string str2 in strArray)
                {
                    this.cm.Items.Add(str2);
                }
                this.cm.Show(this, mousePosition);
                base.Focus();
            }
        }

        private void CreateRightMenu()
        {
            if (this.cmRight == null)
            {
                this.cmRight = new ContextMenuStrip();
                ToolStripItem[] toolStripItems = new ToolStripItem[] { new ToolStripMenuItem("撤销(&U)"), new ToolStripSeparator(), new ToolStripMenuItem("剪切(&T)"), new ToolStripMenuItem("复制(&C)"), new ToolStripMenuItem("粘贴(&P)"), new ToolStripMenuItem("删除(&D)"), new ToolStripSeparator(), new ToolStripMenuItem("全选(&A)"), new ToolStripSeparator(), new ToolStripMenuItem("上标"), new ToolStripMenuItem("下标"), new ToolStripMenuItem("普通文本") };
                this.cmRight.Items.AddRange(toolStripItems);
                this.cmRight.Items.Add(new ToolStripMenuItem("设置"));
                this.cmRight.ItemClicked += new ToolStripItemClickedEventHandler(this.cmRight_ItemClicked);
            }
        }

        private void ReplaceMenuText(string NewText)
        {
            int start = 0;
            int len = 0;
            this.GetMenuTextStartAndLen(ref start, ref len);
            base.Select(start, len);
            this.SelectedText = NewText;
        }

        public void SetSelectionSuperScriptText()
        {
            if (this.SelectionLength > 0)
            {
                base.SelectionFont = new Font(this.Font.FontFamily, 5f);
                base.SelectionCharOffset = 10;
            }
        }

        public void SetSelectionSubScriptText()
        {
            if (this.SelectionLength > 0)
            {
                base.SelectionFont = new Font(this.Font.FontFamily, 5f);
                base.SelectionCharOffset = -10;
            }
        }

        public void SetSelectionNormalScriptText()
        {
            if (this.SelectionLength > 0)
            {
                base.SelectionFont = this.Font;
                base.SelectionCharOffset = 0;
            }
        }

        /// <summary>
        /// 设置行间距、字体
        /// </summary>
        private void f_SetSz()
        { 
            SetControlHjj mSetHjj=new SetControlHjj(this);
            mSetHjj.ShowDialog();
            if(mSetHjj.DialogResult==DialogResult.OK)
            {
                f_SetLineSpace(this, mSetHjj.SLineSpace);
                ChangeFont(mSetHjj.SFontSz.Name, mSetHjj.SFontSz.Size, this);
            }
        }

        /// <summary>  
        /// 设置字体种类,对应于字体下拉框选项  
        /// </summary>  
        /// <param name="fontName">被选中的字体名</param>  
        private void ChangeFont(string fontName, float fontSize, RichTextBox curRichTextBox)
        {
            if (fontName == string.Empty)
                throw new System.Exception("字体名称参数错误，不能为空");
            RichTextBox tempRichTextBox = new RichTextBox();  //用于保存被选中文本的副本  

            //curRichTextBox是当前文本，即原型  
            int curRtbStart = 0;
            int len = curRichTextBox.Text.Length;
            int tempRtbStart = 0;
            Font font = curRichTextBox.SelectionFont;
            //if (len <= 1 && null != font)
            //{
            //    curRichTextBox.SelectAll();
            //    curRichTextBox.SelectionFont = new Font(fontName, fontSize, font.Style);
            //    this.Select(0, 0);
            //    return;
            //}
            tempRichTextBox.Rtf = curRichTextBox.Rtf;
            for (int i = 0; i < len; i++)  //逐个设置字体种类  
            {
                tempRichTextBox.Select(tempRtbStart + i, 1);
                tempRichTextBox.SelectionFont =
                    new Font(fontName, fontSize,
                             tempRichTextBox.SelectionFont.Style);
            }
            //将副本内容插入到到原型中  
            tempRichTextBox.Select(tempRtbStart, len);
            curRichTextBox.Rtf = tempRichTextBox.Rtf;
            this.Select(0, 0);
            curRichTextBox.Focus();
        }

        private void cmRight_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
        {
            switch (this.cmRight.Items.IndexOf(e.ClickedItem))
            {
                case 0:
                    SendKeys.Send("^z");
                    break;

                case 2:
                    //SendKeys.Send("^x");
                    Clipboard.SetData(DataFormats.Text, this.SelectedText);
                    this.SelectedText = "";
                    break;

                case 3:
                    //SendKeys.Send("^c");
                    Clipboard.SetData(DataFormats.Text, this.SelectedText);
                    break;

                case 4:
                    //SendKeys.Send("^v");
                    this.Paste();
                    break;

                case 5:
                    SendKeys.Send("{DEL}");
                    break;

                case 7:
                    SendKeys.Send("^a");
                    break;

                case 9:
                    this.SetSelectionSuperScriptText();
                    break;

                case 10:
                    this.SetSelectionSubScriptText();
                    break;

                case 11:
                    this.SetSelectionNormalScriptText();
                    break;

                case 12:
                    this.f_SetSz();
                    break;
            }
        }

        private void txt_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            Color selectColor = new Color();
            int k = 0;
            int j = 0;
            this.Select(((RichTextBox)sender).GetCharIndexFromPosition(e.Location), 1);
            selectColor = this.SelectionColor;

            if (selectColor == Color.Black) { return; }

            for (int i = 0;
                this.SelectionColor == selectColor && this.SelectedText != "";
                this.Select(((RichTextBox)sender).GetCharIndexFromPosition(e.Location) + i, 1))
            {
                i++;
                k = i;
            }

            this.Select(((RichTextBox)sender).GetCharIndexFromPosition(e.Location), 1);

            for (int i = 0;
                 this.SelectionColor == selectColor && this.SelectedText != "";
                 this.Select(((RichTextBox)sender).GetCharIndexFromPosition(e.Location) - i, 1))
            {
                i++;
                j = i;
                if (
                      (((RichTextBox)sender).GetCharIndexFromPosition(e.Location) - i) == -1
                    )
                {
                    break;
                }
            }

            this.Select(((RichTextBox)sender).GetCharIndexFromPosition(e.Location) - j + 1, k + j - 1);
            if ((base.SelectionFont != null) && base.SelectionFont.Underline)
            {
                this.ShowMenu(e.Location);
            }

            if (this.showMenuOnDoubleClick && (base.SelectionFont != null))
            {
                this.SelectionLength = 0;
                if (base.SelectionFont.Underline)
                {
                    this.ShowMenu(e.Location);
                }
            }
        }

        private void cm_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
        {
            this.ReplaceMenuText(e.ClickedItem.Text);
        }

        private void txt_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                //if ((base.SelectionFont != null) && base.SelectionFont.Underline)
                //{
                //    this.ShowMenu(e.Location);
                //}
            }
            else
            {
                this.CreateRightMenu();
                if (this.SelectedText.Length > 0)
                {
                    this.cmRight.Items[2].Enabled = true;
                    this.cmRight.Items[3].Enabled = true;
                    this.cmRight.Items[5].Enabled = true;
                }
                else
                {
                    this.cmRight.Items[2].Enabled = false;
                    this.cmRight.Items[3].Enabled = false;
                    this.cmRight.Items[5].Enabled = false;
                }
                this.cmRight.Items[4].Enabled = Clipboard.GetText().Length > 0;
                this.cmRight.Items[7].Enabled = this.Text.Length > 0;
                if (base.ReadOnly)
                {
                    this.cmRight.Items[0].Enabled = false;
                    this.cmRight.Items[2].Enabled = false;
                    this.cmRight.Items[4].Enabled = false;
                    this.cmRight.Items[5].Enabled = false;
                }
                this.cmRight.Show(this, e.Location);
            }
        }

        private void cm_KeyPress(object sender, KeyPressEventArgs e)
        {
            this.cm.Visible = false;
            try
            {
                SendKeys.Send(e.KeyChar.ToString());
                e.Handled = true;
            }
            catch
            {
            }
        }

        protected override bool ProcessCmdKey(ref Message m, Keys keyData)
        {
            if (keyData == Keys.Enter)
            {
                if (this.SelectionStart < this.Text.Length)
                {
                    int mSelectLeg = 0;
                    int mSelectStart = 0;
                    //选择了多个字符 选中的文字格式不一致 该判断是否选择的文字都有下划线
                    if (this.SelectionFont == null)
                    {
                        mSelectStart = this.SelectionStart;     //记录下选择文字的起始位置
                        mSelectLeg = this.SelectionLength;      //记录下选择文字的长度
                        //由于可能当前选择的文本中有多种字体 使用SelectionFont的时候无法获取字体为null 所以首先把取消选中
                        this.SelectionLength = 0;
                        int i = this.SelectionStart;
                        //判断选中文字中是否都有下划线 这里用 < 由于对选中的文字中开始的FONT即使是有下滑线也是以前一个字符的格式为标准，所以有了循环中首先把光标位置往后移动一位
                        for (; i < mSelectStart + mSelectLeg; i++)
                        {
                            this.SelectionStart++;
                            //如果判断到有没有下滑线的就不需要跳转了
                            if (this.SelectionFont.Underline == false)
                            {
                                //还原原来文本选择
                                this.Select(mSelectStart, mSelectLeg);
                                return base.ProcessCmdKey(ref m, keyData);
                            }
                        }
                    }

                    //如果是有下划线表示要进行回车转义
                    if (this.SelectionFont.Underline == true)
                    {
                        //光标定位到不是选中文本处
                        int i = this.SelectionStart + this.SelectionLength;
                        //设置选中的文本长度为0
                        this.SelectionLength = 0;
                        for (; i <= this.Text.Length; i++)
                        {
                            this.SelectionStart = i;
                            //使光标定位到没有下划线的文本处
                            if (this.SelectionFont.Underline != true)
                            {
                                break;
                            }
                        }
                        //有下划线文字的长度
                        int Sl = 0;
                        for (; i <= this.Text.Length; i++)
                        {
                            this.SelectionStart = i;
                            if (this.SelectionFont.Underline == true)
                            {
                                //如果有下划线开始记录下划线文字的长度
                                Sl++;
                            }
                            else
                            {
                                //当有记录下长度的时候表示之前有找到下划线的开始
                                if (Sl > 0)
                                {
                                    if (i - Sl < 0)
                                    {
                                        break;
                                    }
                                    //光标定位到这次有下划线文字的第一个字的最前面，并且选择所有下划线 由于这个时候光标定位于有下划线字体的后面一个字上 所以要在减1
                                    this.Select(i - (Sl + 1), Sl);
                                    break;
                                }
                            }
                            if (i == this.Text.Length)
                            {
                                //当有记录下长度的时候表示之前有找到下划线的开始
                                if (Sl > 0)
                                {
                                    if (i - Sl < 0)
                                    {
                                        break;
                                    }
                                    //光标定位到这次有下划线文字的第一个字的最前面，并且选择所有下划线
                                    this.Select(i - (Sl), Sl);
                                    break;
                                }
                            }
                        }
                        return true;
                    }
                }
            }
            return base.ProcessCmdKey(ref m, keyData);
        }

        #region 设置richtextbox行距

        private const int WM_USER = 0x0400;
        private const int EM_GETPARAFORMAT = WM_USER + 61;
        private const int EM_SETPARAFORMAT = WM_USER + 71;
        private const long MAX_TAB_STOPS = 32;
        private const uint PFM_LINESPACING = 0x00000100;
        [StructLayout(LayoutKind.Sequential)]
        private struct PARAFORMAT2
        {
            public int cbSize;
            public uint dwMask;
            public short wNumbering;
            public short wReserved;
            public int dxStartIndent;
            public int dxRightIndent;
            public int dxOffset;
            public short wAlignment;
            public short cTabCount;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
            public int[] rgxTabs;
            public int dySpaceBefore;
            public int dySpaceAfter;
            public int dyLineSpacing;
            public short sStyle;
            public byte bLineSpacingRule;
            public byte bOutlineLevel;
            public short wShadingWeight;
            public short wShadingStyle;
            public short wNumberingStart;
            public short wNumberingStyle;
            public short wNumberingTab;
            public short wBorderSpace;
            public short wBorderWidth;
            public short wBorders;
        }

        [DllImport("user32", CharSet = CharSet.Auto)]
        private static extern IntPtr SendMessage(HandleRef hWnd, int msg, int wParam, ref PARAFORMAT2 lParam);
        /// <summary>
        /// 设置当前控件行间距
        /// </summary>
        /// <param name="ctl"></param>
        /// <param name="dyLineSpacing"></param>
        public static void f_SetLineSpace(Control ctl, int dyLineSpacing)
        {
            PARAFORMAT2 fmt = new PARAFORMAT2();
            fmt.cbSize = Marshal.SizeOf(fmt);
            fmt.bLineSpacingRule = 4;// bLineSpacingRule;
            fmt.dyLineSpacing = dyLineSpacing * 30;
            fmt.dwMask = PFM_LINESPACING;
            try
            {
                int mSelect = 0;
                if (ctl is RichTextBox)
                {
                    mSelect = (ctl as RichTextBox).SelectionStart;
                    (ctl as RichTextBox).SelectAll();
                    SendMessage(new HandleRef(ctl, ctl.Handle), EM_SETPARAFORMAT, 0, ref fmt);
                    (ctl as RichTextBox).SelectionLength = 0;
                    (ctl as RichTextBox).SelectionStart = mSelect;
                }
                else
                {
                    SendMessage(new HandleRef(ctl, ctl.Handle), EM_SETPARAFORMAT, 0, ref fmt);
                }
                
            }
            catch
            {

            }
        }

        #endregion

        protected override void OnDragOver(DragEventArgs drgevent)
        {
            //重写后可以判断是否是自己的文本拖动 定为 如果是自己的文本就是剪切 其他的为赋值
            if (drgevent.Data.GetDataPresent(DataFormats.Text))
                if (mSendThis)
                {
                    drgevent.Effect = DragDropEffects.Move;
                }
                else
                {
                    drgevent.Effect = DragDropEffects.Copy;
                }
            else
                drgevent.Effect = DragDropEffects.None;
            base.OnDragOver(drgevent);
        }

        protected override void OnDragDrop(DragEventArgs drgevent)
        {
            //拖动结束之后设置拖动的对象是其他地方
            mSendThis = false;
            base.OnDragDrop(drgevent);
        }

        protected override void OnMouseDown(MouseEventArgs e)
        {
            //判断是否是自己控件上文字的拖动，如果控件触发了鼠标按下事件，就说明是自己拖动文本
            mSendThis = true;
            base.OnMouseDown(e);
        }

        protected override void OnLeave(EventArgs e)
        {
            //焦点离开之后也设置为false
            mSendThis = false;
            base.OnLeave(e);
        }

    }
}
